import { Actions, GameObjects, Geom, Math, Scene } from 'phaser';
import { Food } from '@/pages/game/snake/classes/Food';
import { blockSize, gridSize } from '@/pages/game/snake/scenes';

const UP = 0;
const DOWN = 1;
const LEFT = 2;
const RIGHT = 3;

export class Snake {
  headPosition: Geom.Point;
  tail: any;
  body: GameObjects.Group;
  head: any;
  key: string;
  alive = true;
  speed = 200;
  moveTime = 0;
  heading = RIGHT;
  direction = RIGHT;

  constructor(scene: Scene, x: number, y: number, key: string) {
    this.headPosition = new Geom.Point(x, y);
    this.tail = new Geom.Point(x, y);
    this.body = scene.add.group();
    this.head = this.body.create(x * blockSize, y * blockSize, key);
    this.head.setOrigin(0);
    this.key = key;
  }

  faceLeft() {
    if (this.direction === UP || this.direction === DOWN) {
      this.heading = LEFT;
    }
  }

  faceRight() {
    if (this.direction === UP || this.direction === DOWN) {
      this.heading = RIGHT;
    }
  }

  faceUp() {
    if (this.direction === LEFT || this.direction === RIGHT) {
      this.heading = UP;
    }
  }

  faceDown() {
    if (this.direction === LEFT || this.direction === RIGHT) {
      this.heading = DOWN;
    }
  }

  update(time: number) {
    if (time >= this.moveTime) {
      return this.move(time);
    }
    return false;
  }

  move(time: number) {
    switch (this.heading) {
      case LEFT:
        this.headPosition.x = Math.Wrap(this.headPosition.x - 1, 0, gridSize.x);
        break;
      case RIGHT:
        this.headPosition.x = Math.Wrap(this.headPosition.x + 1, 0, gridSize.x);
        break;
      case UP:
        this.headPosition.y = Math.Wrap(this.headPosition.y - 1, 0, gridSize.y);
        break;
      case DOWN:
        this.headPosition.y = Math.Wrap(this.headPosition.y + 1, 0, gridSize.y);
        break;
      default:
        break;
    }

    this.direction = this.heading;

    Actions.ShiftPosition(
      this.body.getChildren(),
      this.headPosition.x * blockSize,
      this.headPosition.y * blockSize,
      1,
      this.tail,
    );

    const hitBody = Actions.GetFirst(
      this.body.getChildren(),
      { x: this.head.x, y: this.head.y },
      1,
    );

    if (hitBody) {
      console.log('dead');
      this.alive = false;
      return false;
    }
    this.moveTime = time + this.speed;
    return true;
  }

  grow() {
    const newPart = this.body.create(this.tail.x, this.tail.y, this.key);
    newPart.setOrigin(0);
  }

  collideWithFood(food: Food) {
    if (this.head.x === food.x && this.head.y === food.y) {
      this.grow();
      food.eat();
      if (this.speed > 20 && food.total % 5 === 0) {
        this.speed -= 5;
      }
      return true;
    }
    return false;
  }

  updateGrid(testGrid: boolean[][]) {
    this.body.children.each((segment: any) => {
      const bx = segment.x / blockSize;
      const by = segment.y / blockSize;
      testGrid[by][bx] = false;
    });
    return testGrid;
  }
}
